package org.example.promise;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 类描述：Promise 支持类
 * <br>
 *
 * @author ZS
 * @version 1.0
 * @date 2020/12/29
 **/
public class PromiseSupport<V> implements Future<V> {
    // 定义运行状态
    protected static final int RUNNING = 1;
    protected static final int FAILED = 2;
    protected static final int COMPLETED = 3;

    // 锁对象
    protected final Object lock;

    // 当前状态
    protected volatile int state = RUNNING;
    // 返回值
    protected V value;
    // 异常返回值
    protected Exception exception;

    public PromiseSupport() {
        this.lock = new Object();
    }

    /**
     * 执行成功，将方法返回值回写
     * fulfill:履行
     *
     * @param value 返回值
     */
    protected void fulfill(V value) {
        this.value = value;
        this.state = COMPLETED;
        synchronized (lock) {
            // 方法执行完成，唤醒其他阻塞线程
            // 比如阻塞在get()方法上的线程
            lock.notifyAll();
        }
    }

    /**
     * 执行失败，异常回写
     *
     * @param exception 所执行方法抛出的异常
     */
    protected void fulfillExceptionally(Exception exception) {
        this.exception = exception;
        this.state = FAILED;
        synchronized (lock) {
            // 任务执行过程抛出异常，执行结束
            // 唤醒阻塞在get()方法上的线程
            lock.notifyAll();
        }
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    @Override
    public boolean isCancelled() {
        return false;
    }

    @Override
    public boolean isDone() {
        return state > RUNNING;
    }

    @Override
    public V get() throws InterruptedException, ExecutionException {
        synchronized (lock) {
            // 任务未执行完
            while (state == RUNNING) {
                // 阻塞调用线程
                lock.wait();
            }
        }
        // 任务正常结束，将任务返回值返回
        if (state == COMPLETED) {
            return value;
        }
        // 任务异常结束，将异常抛出
        throw new ExecutionException(exception);
    }

    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        synchronized (lock) {
            // 任务未执行完
            while (state == RUNNING) {
                try {
                    // 定时阻塞调用线程
                    lock.wait(unit.toMillis(timeout));
                } catch (InterruptedException e) {
                    // 打印异常日志
                    System.out.println("Interrupted:" + e.getMessage());
                    // wait()被中断后会清楚线程的中断标识
                    // 重新设置当前线程的中断标志
                    Thread.currentThread().interrupt();
                }
            }
        }
        // 任务正常结束，将任务返回值返回
        if (state == COMPLETED) {
            return value;
        }
        // 任务异常结束，将异常抛出
        throw new ExecutionException(exception);
    }
}
